Skip to content

Always emit LMNR_HTTP_PORT and align chart-default warm LMNR env#738

Merged
ak684 merged 1 commit into
mainfrom
alona/fix-lmnr-warm-runtime-match
Jun 18, 2026
Merged

Always emit LMNR_HTTP_PORT and align chart-default warm LMNR env#738
ak684 merged 1 commit into
mainfrom
alona/fix-lmnr-warm-runtime-match

Conversation

@ak684

@ak684 ak684 commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Problem (#737): every conversation cold-starts on OHE

The runtime-api warm matcher (warm_runtime_matches -> clean_env_for_match) does strict env equality (keys and values), and LMNR_* keys are not in KEYS_TO_CLEAN. So if the request env and a warm pool entry differ on any LMNR_* key, the warm runtime is rejected and the conversation cold-starts.

LMNR_BASE_URL / LMNR_FORCE_HTTP / LMNR_PROJECT_API_KEY are always emitted (="" when off) on both sides and match. But PR #692 (ec2c290) wrapped LMNR_HTTP_PORT in charts/openhands/templates/_env.yaml so the request side OMITS it when laminar.httpPort is unset, while the KOTS warm template (replicated/openhands.yaml:356, anchor &lmnr_http_port reused at :625/:913) still always emits it (="" when analytics off):

only_in_warm=['LMNR_HTTP_PORT']  ->  no warm match  ->  cold start

Fix (quick, teammate-endorsed)

Make the LMNR_* env key set identical on the request side and on both warm paths (KOTS and chart-default), in both toggle states:

  1. Request sidecharts/openhands/templates/_env.yaml: restore LMNR_HTTP_PORT to always-emit ({{ if and .Values.laminar.enabled .Values.laminar.httpPort }}…{{ else }}""{{ end }}), matching the three LMNR_* keys directly above it. This reverts APP-2260: omit LMNR_HTTP_PORT env when httpPort is unset #692's key omission.
  2. Chart-default warm configcharts/runtime-api/values.yaml (warmRuntimes.configs[].environment) and charts/openhands/values.yaml (runtime-api.warmRuntimes override): add the full LMNR_* set (=""). Reverting APP-2260: omit LMNR_HTTP_PORT env when httpPort is unset #692 alone would re-break the chart-default/SaaS path (request LMNR_HTTP_PORT="" but chart-default warm had no LMNR_* keys) — which is what APP-2260: omit LMNR_HTTP_PORT env when httpPort is unset #692 originally papered over. Adding LMNR_* here makes the always-emit revert safe for SaaS.
  3. KOTS warm templatereplicated/openhands.yaml already always-emits all 4 LMNR_* via shared anchors (:354-357 defined, :623-626 + :911-914 reused). Verified consistent; left unchanged.

Why always-passing LMNR_HTTP_PORT="" is safe

OpenHands/openhands/app_server/sandbox/sandbox_spec_service.py:

  • AUTO_FORWARD_PREFIXES = ('LLM_', 'LMNR_')
  • get_agent_server_env() forwards every LMNR_* var from the pod env as-is, including empty values — no special-casing.

The agent only emits Laminar traces when LMNR_PROJECT_API_KEY is configured, so LMNR_HTTP_PORT="" is inert when Laminar is off — exactly like the other three LMNR_* keys, which already ship "" in the off state.

Render proof (helm template)

Request side (openhands deployment) LMNR_* key set, both states:

  • analytics/laminar OFF (default): LMNR_BASE_URL="", LMNR_FORCE_HTTP="", LMNR_HTTP_PORT="", LMNR_PROJECT_API_KEY=""
  • laminar ON (httpPort=8000): same 4 keys, LMNR_HTTP_PORT="8000", LMNR_FORCE_HTTP="true", base-url/api-key via valueFrom

Chart-default warm config (runtime-api warm-runtimes-configmap):

  • {"LMNR_BASE_URL":"","LMNR_FORCE_HTTP":"","LMNR_HTTP_PORT":"","LMNR_PROJECT_API_KEY":"", …}

=> Request LMNR_* key set == chart-default warm LMNR_* key set in both toggle states. KOTS path is equivalent by construction: the anchors render all 4 to "" when analytics_enabled != 1 (matching the off request env) and to real values + laminar.enabled=true/httpPort=8000 when on (matching the on request env). KOTS replaces the whole warmRuntimes.configs array, so the chart-default LMNR_* additions are inert on the KOTS path.

Chart versions

  • openhands 0.7.63 -> 0.7.64
  • runtime-api 0.3.11 -> 0.3.12, and repin openhands -> runtime-api dependency to 0.3.12 (per validate-chart-versions)

Follow-up (deliberately deferred)

The cleaner redesign — thread "is Laminar active" consistently through enterprise-server and runtime-api, or harden runtime-api clean_env_for_match to ignore empty/LMNR_* keys — is intentionally left as a later follow-up. This PR is the minimal always-pass fix.

Closes #737

The runtime-api warm matcher does strict env equality (clean_env_for_match);
LMNR_* keys are not in KEYS_TO_CLEAN, so a missing/extra LMNR key forces a
cold start. PR #692 (ec2c290) wrapped LMNR_HTTP_PORT so the request side OMITS
it when laminar.httpPort is unset, but the KOTS warm template still always
emits all 4 LMNR_* (="" when analytics off) -> only_in_warm=['LMNR_HTTP_PORT']
-> every conversation cold-starts on OHE.

Quick, teammate-endorsed fix: make the LMNR_* key set identical on the request
side and both warm paths in either toggle state.

- _env.yaml: restore LMNR_HTTP_PORT to always-emit (="" when off), matching
  the other three LMNR_* just above (reverts #692's key omission).
- chart-default warm configs (runtime-api + openhands runtime-api override):
  add LMNR_* (="") so reverting #692 does not re-break the SaaS/chart-default
  path #692 fixed.
- KOTS warm template already always-emits all 4 LMNR_* via shared anchors; kept.

Safe because get_agent_server_env auto-forwards all LMNR_* uniformly and the
agent only traces when LMNR_PROJECT_API_KEY is set, so LMNR_HTTP_PORT="" is
inert (the other 3 already ship "" when off).

The cleaner redesign (thread laminar-active consistently through
enterprise-server + runtime-api, or harden clean_env_for_match to ignore
empty/LMNR_* keys) is a deliberate follow-up.

Bump openhands (0.7.64) + runtime-api (0.3.12) chart versions and repin
openhands' runtime-api dependency to 0.3.12.

Closes #737

@juanmichelini juanmichelini left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ak684 ak684 merged commit aa5a2e8 into main Jun 18, 2026
27 checks passed
@ak684 ak684 deleted the alona/fix-lmnr-warm-runtime-match branch June 18, 2026 19:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Warm-runtime reuse broken on OHE (1.38.x): LMNR_HTTP_PORT env asymmetry forces every conversation to cold-start

2 participants